在前面我們實踐了 Login 並取得 JWT
。
接著,在 Access 時,我們會需要 Send 一個 Auth request 給 Server,然後,Server 端會比較 JWT,最後回傳 response 給 Client 端。
在 access 的時候,會將 JWT
帶入 request header,接著,我們會藉由在 server 中比較 JWT
,再返回 request。
取得 token
接收 Client 傳來的 header ,並取得 JWT
驗證 token
確認 user 是否還存在
避免在認證完 token 後,user 被 delete
確認是否在 issue 發出去後,user 改動了 password
Password 被更動,應該要重新取得 JWT
允許進入被受保護的 route
以下為範例:
protect router
// 會先運行 authController.protect,執行成功後再運行 testController.getAllTests (此處主要是保護 getAllTests 這個 routes)
router
.route('/')
.get(authController.protect, testController.getAllTests)
.post(testController.createTest)
protect function:
exports.protect = async (req, res, next) => {
// 1. 取得 token
let token;
// 此處會依照開頭是否是 Bearer 來作為判斷依據的原因:
// 因為這邊預設 request 的 header 是帶上: "Bearer ${JWT_TOKEN}"
if(
req.headers.authentication &&
req.headers.autrhntication.startWith('Bearer')
) {
token = req.headers.authorization.split(' ')[1];
}
if (!token) {
return next (
new AppError('Please Log in to get access', 401);
);
}
// 2. 驗證 token
// 此處使用 promisify 是想要把 jwt.verify 轉換成 promise 版本,避免 Error first call-back
const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET);
// 3. 確認 user 是否還存在
const freshUser = await User.findById(decoded.id);
if(!freshUser) {
return next(new AppError('The token belonging to this user does no longer exist.', 401));
}
// 4. 確認是否在 token 發出去後,user 改動了 password
// 此處使用到的 changedPasswordAfter function 寫在下一個程式碼區塊
// 這邊的 iat 是指 指示 JWT 發佈時間的時間戳,有興趣可以回之前的規劃篇看看 ~
if (freshUser.changedPasswordAfter(decoded.iat)) {
return next(new AppError('Password has been changed recently. Please login again.', 401));
}
// 5. 允許進入被受保護的 route
req.user = freshUser;
next();
}
changedPasswordAfter() function:
userSchema.methods.changedPasswordAfter = function(JWTTimestamp) {
// 此處為原本有的 passwordChangedAt 參數
if (this.passwordChangedAt) {
const changedTimestamp = parseInt(
this.passwordChangedAt.getTime() / 1000, 10);
return JWTTimestamp = changedTimestamp;
}
return false;
}
在上述程式碼中,我們並沒有特別處理 Error 的管理部分,
所以當出現了非預期的 Error,可能就整個系統 crash 了!
回顧我們先前的文章,還記得 Error Handling 的重要性吧XD
我們在上述程式碼說明了 JWT
的驗證實作,但我們都沒有處理 Error Handling! 這會是一個致命傷。
我們將會在下次一次說明 Error Handling 的問題,production 環境 & 非 production 環境 error message 的差異 ~
下次 Error Handling 感覺又可以寫一篇,不過感覺自己越學習越多越充實~ 雖然經驗還沒有很足,但我想可以越了解越多也是好事 :D
Udemy Node.js, Express, MongoDB & More: The Complete Bootcamp 2023
https://www.udemy.com/course/nodejs-express-mongodb-bootcamp/
Hacksplaining:
https://www.hacksplaining.com/